package com.itlong.cloud.intercept.sdkV3;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.PO.OperateUserInfoPO;
import com.itlong.cloud.POJO.PO.PropertyUserInfoPO;
import com.itlong.cloud.POJO.VO.SDKMessageVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.ErrorTypeEnum;
import com.itlong.cloud.enumerate.PropertyPublicRoleEnum;
import com.itlong.cloud.enumerate.ecode.*;
import com.itlong.cloud.intercept.sdkV1.CloudTalkSDKServerLoginIntercept;
import com.itlong.cloud.project.operate.IOperateProjectServiceClient;
import com.itlong.cloud.user.operate.IOperatePropertyAccountServiceClient;
import com.itlong.cloud.user.operate.IOperateUserInfoServiceClient;
import com.itlong.cloud.user.sdk.ICloudTalkSDKAppUserServiceClient;
import com.itlong.cloud.user.sdk.ICloudTalkSDKServerUserServiceClient;
import com.itlong.cloud.user.sdk.ISDKServerOldUserServiceClient;
import com.itlong.cloud.utils.encrypt.EncryptUtil;
import com.itlong.cloud.utils.network.http.HttpProtocolUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.tool.DeviceUtil;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * <desc>
 * 云设备 入参处理拦截器
 * </desc>
 *
 * @createDate 2019/09/16
 */
@Aspect
@Component
@Order(9)
public class SDKCloudDeviceParamIntercept {
    private static Logger LOG = LoggerFactory.getLogger(CloudTalkSDKServerLoginIntercept.class);

    @Autowired
    ICloudTalkSDKServerUserServiceClient iCloudTalkSDKServerUserServiceClient;

    @Autowired
    ISDKServerOldUserServiceClient iSDKUserServiceClient;

    @Autowired
    ICloudTalkSDKAppUserServiceClient iCloudTalkSDKAppUserServiceClient;

    @Autowired
    IOperateUserInfoServiceClient iOperateUserInfoServiceClient;

    @Autowired
    IOperatePropertyAccountServiceClient iOperatePropertyAccountServiceClient;

    @Autowired
    IOperateProjectServiceClient iOperateProjectServiceClient;

    // 定义一个切入点
    @Pointcut("(execution(* com.itlong.cloud.controller.sdkV3.base.*.*(..)) || execution(* com.itlong.cloud.controller.sdkV3.elevator.*.*(..))" +
            "|| execution(* com.itlong.cloud.controller.sdkV3.entrance.*.*(..)) || execution(* com.itlong.cloud.controller.sdkV3.face.*.*(..)) " +
            "|| execution(* com.itlong.cloud.controller.sdkV3.intercom.server.SDKCloudTalkEquipController.*(..))|| execution(* com.itlong.cloud.controller.sdkV3.intercom.server.SDKCloudTalkUserController.*(..)))" +
            "&& !@annotation(com.itlong.cloud.annotation.UnAuthAccessRequired)")
    public void excudeService() {
    }

    /**
     * <desc>
     * 云设备 入参token拦截器
     * </desc>
     *
     * @param thisJoinPoint
     * @return
     * @author Qiang.S
     * @createDate 2019/09/16
     */
    @Around("excudeService()")
    public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String token = request.getParameter("token");
        String responseTimestamp = new Date().getTime() + "";
        Date nowTime = new Date();
        if (StringUtils.isBlank(token)) { //无token
            LOG.error("token不能为空！", ErrorTypeEnum.PARAMETER_ANOMALY.getName());
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return new SDKMessageVO(SDKErrorCodeEnum.SDK_PARAM_TOKEN_ERR.getErrorCode(), "", responseTimestamp, "");//此时没有加密签名直接明文返回报错信息
        }
        //兼容没有项目的账号退出robotGo
        String uri = request.getRequestURI();
        boolean logoutFlag = false;
        if (uri.contains("logout")) {
            logoutFlag = true;
        }
        PropertyUserInfoPO propertyUserInfoPO = iCloudTalkSDKAppUserServiceClient.developerRetrieve(token);
        if (propertyUserInfoPO == null) { //appId 错误导致无法查询出开发者信息
            LOG.error("token解析失败！", ErrorTypeEnum.PARAMETER_ANOMALY.getName());
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return new SDKMessageVO(SDKErrorCodeEnum.SDK_PARAM_TOKEN_ERR.getErrorCode(), "", responseTimestamp, "");//此时没有加密签名直接明文返回报错信息
        }
        String encryptType = propertyUserInfoPO.getEncryptType();
        LOG.info("解密方式：{}", encryptType);
        PropertyUserInfoPO statusPO = iSDKUserServiceClient.getPropertyUserByAppId(propertyUserInfoPO.getUserId());
        //为了兼容工程人员登录，再查运营用户信息表
        if (statusPO == null) {
            statusPO = new PropertyUserInfoPO();
            OperateUserInfoPO po = new OperateUserInfoPO();
            po.setUserId(propertyUserInfoPO.getUserId());
            OperateUserInfoPO userInfoPO = iOperateUserInfoServiceClient.getOne(po);
            if (userInfoPO == null) {
                statusPO.setStatus(DataStatusEnum.DELETE.getType());
            } else {
                statusPO.setStatus(userInfoPO.getStatus());
            }
        }
        if (statusPO.getStatus() != 1) {
            LOG.error("开发者已被禁用！,{},userid:{}", ErrorTypeEnum.VERIFY_ANOMALY.getName(), propertyUserInfoPO.getUserId());
            return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKErrorCodeEnum.SDK_DEVELOPER_STATUS_ERR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
        }

        //判断机器人账号授权是否过有效期，
        // 为了区分robotgo调用sdk接口和直接调用sdk接口现在使用loginType字段区分，直接调用sdk接口不存储loginType
        if (PropertyPublicRoleEnum.ROBOT_DEVELOPER.getRoleId().equals(statusPO.getRoleId())
                && "1".equals(propertyUserInfoPO.getLoginType())
                && (nowTime.before(statusPO.getEffectStartTime())
                || nowTime.after(statusPO.getEffectEndTime()))) {
            LOG.error("机器人账号授权已过期！,{},userid:{}", ErrorTypeEnum.VERIFY_ANOMALY.getName(), propertyUserInfoPO.getUserId());
            return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(OperateErrorCodeEnum.USER_ACCOUNT_EXPIRE_ERR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
        }

        String requestId;
        Map<String, Object> params;
        try {
            request.setAttribute("encryptType", encryptType);
            //入参密文
            String encryptScript = request.getParameter("encryptScript");
            LOG.info("encryptScript===>{}", encryptScript);
            if (StringUtils.isBlank(encryptScript)) { //加密串未携带，参数异常
                LOG.error("解密参数为空!", ErrorTypeEnum.PARAMETER_ANOMALY.getName());
                return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.ENCRYPT_ERROR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
            } else {
                //解密入参
                String encryptResult = EncryptUtil.decrypt(encryptScript, propertyUserInfoPO.getAppsecret(), encryptType);
                LOG.info("encryptResult===>{}", encryptResult);
                encryptResult = encryptResult.replaceAll("&quot;", "\"");
                if (encryptResult == null) {
                    LOG.error("解密失败!", ErrorTypeEnum.PARAMETER_ANOMALY.getName());
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.ENCRYPT_ERROR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }

                JSONObject paras = JSONObject.parseObject(encryptResult);//入参转json
                params = JsonUtil.toObject(paras.toString(), HashMap.class);
                requestId = Optional.ofNullable(params.get("requestId")).orElse("").toString();
                String deviceUnique = Optional.ofNullable(params.get("deviceUnique")).orElse("").toString();
                if (StringUtils.isNotEmpty(deviceUnique)) {
                    if (!DeviceUtil.isDeviceUnique(deviceUnique)) {
                        LOG.error("设备编码格式错误!,{},deviceUnique:{}", ErrorTypeEnum.PARAMETER_ANOMALY.getName(), deviceUnique);
                        return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.DEVICE_UNIQUE_ERROR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                    }
                    String projectId = DeviceUtil.getProjectIdByDeviceUnique(params.get("deviceUnique").toString());
                    params.put("projectId", projectId);
                }
                MDC.put(PlatformConstants.REQUEST_ID, requestId);
                String robotId = Optional.ofNullable(params.get("robotId")).orElse("").toString();
                String timestamp = Optional.ofNullable(params.get("timestamp")).orElse("").toString();
                if (!timestamp.matches("[0-9]{13}")) {
                    LOG.error("timestamp不符合规范,{},timestamp:{}！", ErrorTypeEnum.PARAMETER_ANOMALY.getName(), timestamp);
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.TIMESTAMP_VERIFY_ERROR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
                if (requestId.length() > 32 || requestId.length() < 1) {
                    LOG.error("requestId长度不符合规范，应该为1-32位！,{},requestId:{}", ErrorTypeEnum.PARAMETER_ANOMALY.getName(), requestId);
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.REQUEST_ID_LENGTH_ERROR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
                if (StringUtils.isEmpty(robotId)) {
                    LOG.error("机器人编号不能为空！", ErrorTypeEnum.PARAMETER_ANOMALY.getName());
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.ROBOT_ID_VERIFY_ERROR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
                //获取项目编号
                String projectId = robotId.substring(0, 8);
                Integer projectStatus = iOperateProjectServiceClient.getProjectStatus(projectId);
                //判断项目是否启用
                if (!"1".equals(projectStatus + "")) {
                    LOG.error("项目未启用！", ErrorTypeEnum.VERIFY_ANOMALY.getName());
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.PROJECT_IS_NOT_ACTIVATED.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
                if (!robotId.equals(propertyUserInfoPO.getRobotId())) {
                    LOG.error("robotId和登录时不一致,{},{}", ErrorTypeEnum.VERIFY_ANOMALY.getName(), robotId);
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(CloudTalkErrorCodeEnum.SERVER_SDK_ROBOT_ID_NO_IDENTICAL_ERR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
//                //验签
//                String sign = params.get("sign").toString();
//                params.remove("sign");
//                if (!EncryptUtil.checkSDKV3Sign(params, propertyUserInfoPO.getAppsecret(), sign, encryptType)) {
//                    return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(CloudTalkErrorCodeEnum.SERVER_MD5_ERROR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret());
//                }
                HttpProtocolUtil.setRequestAttributes(params, request);
                //通过appId appSecret来进行服务认证
                if (StringUtils.isNotBlank(propertyUserInfoPO.getUserId()) && StringUtils.isNotBlank(propertyUserInfoPO.getAppsecret())) {
                    // 校验开发者账号是否有该项目的权限
                    List<String> projectIdList = iCloudTalkSDKServerUserServiceClient.getProjectIdByParams(propertyUserInfoPO.getUserId());
                    //兼容工程人员登录robotGo
                    if (projectIdList == null || projectIdList.isEmpty()) {
                        projectIdList = iOperatePropertyAccountServiceClient.getEngineerProjectIds(propertyUserInfoPO.getUserId());
                    }
                    if (null != params.get("projectId") && (projectIdList == null || !projectIdList.contains(params.get("projectId"))) && !logoutFlag) {
                        LOG.error("开发者没有项目权限或项目权限已过期，{},{}", ErrorTypeEnum.VERIFY_ANOMALY.getName(), params.get("projectId"));
                        return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(CloudTalkErrorCodeEnum.SERVER_CHECKDEVELOPER_AUTH.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                    }
                    request.setAttribute("appId", propertyUserInfoPO.getUserId());
                    request.setAttribute("appSecret", propertyUserInfoPO.getAppsecret());
                    request.setAttribute("roleId", propertyUserInfoPO.getRoleId());
                    Object result = thisJoinPoint.proceed();
                    //加密
                    //SDKMessageVO messageVO = (SDKMessageVO) result;
                    //return EncryptUtil.getEncryptResultSDKV3(messageVO, propertyUserInfoPO.getAppsecret(), encryptType);
                    return EncryptUtil.getEncryptResultSDKV3(result, propertyUserInfoPO.getAppsecret(), encryptType);
                } else {
                    LOG.error("用户ID或者秘钥为空,{},userid:{},appsecret:{}", ErrorTypeEnum.PARAMETER_ANOMALY.getName(), propertyUserInfoPO.getUserId(), propertyUserInfoPO.getAppsecret());
                    return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.USER_ID_OR_APP_SECRET_ERROR.getErrorCode(), requestId, responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
                }
            }
        } catch (JSONException e) {
            LOG.error("解密异常，json解析失败,{}", ErrorTypeEnum.SYSTEM_ANOMALY.getName(), e);
            return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(SDKV3ErrorCodeEnum.ENCRYPT_ERROR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
        } catch (Exception e) {
            LOG.error("系统异常,{}", ErrorTypeEnum.SYSTEM_ANOMALY.getName(), e);
            return EncryptUtil.getEncryptResultSDKV3(new SDKMessageVO(BaseErrorCodeEnum.ERROR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret(), encryptType);
        }
    }
}